/**
 * @file      adc.h
 * @author    chipsea
 * @brief     Contains all functions support for adc driver
 * @version   0.1
 * @date      2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */
#ifndef __ADC__H__
#define __ADC__H__

#ifdef __cplusplus
extern "C" {
#endif

#include "types.h"
#include "gpio.h"

#define    MAX_ADC_SAMPLE_SIZE     32
#define    ADC_CH_BASE             (0x40050400UL)

#define    ENABLE_ADC_INT       AP_ADCC->intr_mask |= 0x000001ff
#define    MASK_ADC_INT         AP_ADCC->intr_mask &= 0xfffffe00

#define    CLEAR_ADC_INT(n)       AP_ADC->intr_clear |= BIT(n)


#define    IS_CLAER_ADC_INT_VOICE (AP_ADC->intr_clear & BIT(8))
#define    IS_CLAER_ADC_INT(n)    (AP_ADC->intr_clear & BIT(n))
    
#define    GET_IRQ_STATUS         (AP_ADCC->intr_status & 0x3ff)

#define    ENABLE_ADC             (AP_PCRM->ANA_CTL |= BIT(3))
#define    DISABLE_ADC            (AP_PCRM->ANA_CTL &= ~BIT(3))
    
#define    ADC_CLOCK_ENABLE       (AP_PCRM->CLKHF_CTL1 |= BIT(13))
#define    ADC_CLOCK_DISABLE      (AP_PCRM->CLKHF_CTL1 &= ~BIT(13))

#define    ADC_CH0_POINTER    (AP_ADCC->int_pointer_ch0_ch3 & 0x0000003f)
#define    ADC_CH1_POINTER    (AP_ADCC->int_pointer_ch0_ch3 & (0x0000003f << 6))>>6
#define    ADC_CH2_POINTER    (AP_ADCC->int_pointer_ch0_ch3 & (0x0000003f << 12))>>12
#define    ADC_CH3_POINTER    (AP_ADCC->int_pointer_ch0_ch3 & (0x0000003f << 18))>>18
#define    ADC_CH4_POINTER    (AP_ADCC->int_pointer_ch4_ch7 & 0x0000003f)
#define    ADC_CH5_POINTER    (AP_ADCC->int_pointer_ch4_ch7 & (0x0000003f << 6))>>6
#define    ADC_CH6_POINTER    (AP_ADCC->int_pointer_ch4_ch7 & (0x0000003f << 12))>>12
#define    ADC_CH7_POINTER    (AP_ADCC->int_pointer_ch4_ch7 & (0x0000003f << 18))>>18

#define    SPIF_RSVD_AREA_1                (0x1008)
#define    pSPIF_RSVD1_ADC_CALIBRATE       ((volatile uint32_t*)(SPIF_BASE_ADDR + SPIF_RSVD_AREA_1))
#define    SPIF_RSVD1_ADC_CALIBRATE        (SPIF_BASE_ADDR + SPIF_RSVD_AREA_1)

/**
* @enum  AdcChannel_t
* @brief adc channel enum
*/
typedef enum {
    ADC_CH0DIFF = 1,/*p18(positive),p25(negative),only works in diff*/
    ADC_CH0 = 2,ADC_CH1N_P11 = 2,MIN_ADC_CH = 2,
    ADC_CH1 = 3,ADC_CH1P_P23 = 3,/*P23 and P11*/
    ADC_CH2 = 4,ADC_CH2N_P24 = 4,
    ADC_CH3 = 5,ADC_CH2P_P14 = 5,/*P14 and P24*/
    ADC_CH4 = 6,ADC_CH3N_P15 = 6,
    ADC_CH9 = 7,ADC_CH3P_P20 = 7,MAX_ADC_CH = 7,/*P20 and P15*/
    ADC_CH_VOICE = 8,
    ADC_CH_NUM =9,
}AdcChannel_t;

#define ADC_BIT(ch) (1<<ch)

/**
* @enum  adc evt
* @brief adc type evt
*/
enum{
  HAL_ADC_EVT_DATA = 1,
  HAL_ADC_EVT_FAIL = 0xff
};

/**
* @enum  AdcClockSel_t
* @brief adc sample frequency enum
*/
typedef enum {
    HAL_ADC_CLOCK_80K = 0,
    HAL_ADC_CLOCK_160K = 1,
    HAL_ADC_CLOCK_320K = 2,
}AdcClockSel_t;

/**
* @struct AdcCfg_t
* @brief  adc config struct
*/
typedef struct _adc_Cfg_t{
    uint8_t channel_flag;        //select channel
    bool  is_continue_mode;      //ture:manual false:auto
    uint8_t  is_high_resolution; //[bit7~bit2]=[p20,p15~p11],ignore[bit1,bit0], if bit is 0, it is bypass; otherwise, it is attenuated mode
}AdcCfg_t;

/**
* @struct  adcEvt_t
* @brief   adc callback parameters struct
*/
typedef struct _adc_Evt_t{
  int           type;
  AdcChannel_t  ch;
  uint16_t*     data;
  uint8_t       size; //word size
}AdcEvt_t;

/**
* @callback adc_Hdl_t
* @brief    adc event callback pointer
*/
typedef void (*adc_Hdl_t)(AdcEvt_t* pev);

/**
* @array s_pinmap
* @brief adc channel array
*/
extern GpioPin_t s_pinmap[ADC_CH_NUM];

/**
 * @fn      HalAdcInit
 * @brief   This function process for adc initial
 * @param   none
 * @return  none
 */
void HalAdcInit(void);

/**
 * @fn      HalAdcChannelConfig
 * @brief   This function process for adc config
 * @param   cfg          adc initial struct
            handler      adc interrupt callback
 * @return  ErrCode_t
 */
int HalAdcChannelConfig(AdcCfg_t cfg, adc_Hdl_t evt_handler);

/**
 * @fn      HalAdcClockConfig
 * @brief   This function process for adc sample frequency
 * @param   clk      adc sampling rate
 * @return  ErrCode_t
 */
int HalAdcClockConfig(AdcClockSel_t clk);

/**
 * @fn      HalAdcStart
 * @brief   start adc
 * @param   none
 * @return  ErrCode_t
 */
int HalAdcStart(void);

/**
 * @fn      HalAdcStop
 * @brief   stop adc
 * @param   none
 * @return  ErrCode_t
 */
int HalAdcStop(void);

/**
 * @fn      HalAdcIRQHandler
 * @brief   This function process for adc interrupt
 * @param   none
 * @return  none
 */
void __attribute__((weak)) HalAdcIRQHandler(void);

/**
 * @fn      HalAdcValueCal
 * @brief   This function calculate the real time vol value
 * @param   ch           adc channel
            *buf         adc sample data
            size         data size
            high_resol   work mode
 * @return  vol value
 */
int32_t HalAdcValueCal(AdcChannel_t ch,uint16_t* buf, uint32_t size, uint8_t high_resol);

#ifdef __cplusplus
}
#endif

#endif
